package com.github.blanexie.nexusj.torrent.domain.entity


import cn.hutool.core.io.FileUtil
import cn.hutool.core.io.resource.ClassPathResource
import cn.hutool.json.JSONUtil
import com.github.blanexie.nexusj.support.UploadFile
import com.github.blanexie.nexusj.support.database
import com.github.blanexie.nexusj.support.setting
import com.github.blanexie.nexusj.torrent.infra.repository.TorrentDO
import com.github.blanexie.nexusj.torrent.domain.valobj.*
import org.ktorm.dsl.*
import java.io.File
import java.io.InputStream
import java.nio.ByteBuffer
import java.time.LocalDateTime

val torrentPath = setting["torrent.path"]!!

data class TorrentEntity(
    val infoHash: String,
    val title: String,  //标题
    var ration: Ration?, // 倍率设置
    val torrentFile: TorrentFile,
    val category: Category,
    var label: List<Label>,
    var coverPath: File?,//封面, 有些资源没有封面, 比如小说等
    val description: Description,  //描述信息
    var status: Int = 0,
    val createTime: LocalDateTime = LocalDateTime.now(),
    var updateTime: LocalDateTime = LocalDateTime.now()
) {

    /**
     * 下载torrent
     */
    fun download(): File {
        return torrentFile.cacheFile()
    }

    fun save() {
        val infoHash = database().from(TorrentDO).select(TorrentDO.infoHash).where {
            TorrentDO.infoHash eq infoHash
        }.map { row -> row.getString("info_hash") }.last()

        if (infoHash != null) {
            database().update(TorrentDO) {
                set(TorrentDO.title, title)
                set(TorrentDO.category, category.code)
                //  set(Torrent.completeCount)
                set(TorrentDO.coverPath, coverPath?.absolutePath?.replaceFirst(torrentPath, ""))
                set(TorrentDO.createTime, createTime)
                set(TorrentDO.updateTime, updateTime)
                set(TorrentDO.status, status)
                //description
                set(TorrentDO.descImgs, description.imgs?.map { it.absolutePath.replaceFirst(torrentPath, "") })
                set(TorrentDO.description, description.content)
                //torrent
                set(TorrentDO.announce, torrentFile.announce)
                set(TorrentDO.announceList, torrentFile.announceList)
                set(TorrentDO.comment, torrentFile.comment)
                set(TorrentDO.commentUtf8, torrentFile.commentUtf8)
                set(TorrentDO.creationDate, torrentFile.creationDate)
                set(TorrentDO.encoding, torrentFile.encoding)
                set(TorrentDO.nodes, torrentFile.nodes)
                //info
                set(TorrentDO.length, torrentFile.info.length)
                set(TorrentDO.files, torrentFile.info.files)
                set(TorrentDO.name, torrentFile.info.name)
                set(TorrentDO.nameUtf8, torrentFile.info.nameUtf8)
                set(TorrentDO.pieceLength, torrentFile.info.pieceLength)
                set(TorrentDO.pieces, torrentFile.info.pieces.array())
                set(TorrentDO.publisher, torrentFile.info.publisher)
                set(TorrentDO.publisherUtf8, torrentFile.info.publisherUtf8)
                set(TorrentDO.publisherUrl, torrentFile.info.publisherUrl)
                set(TorrentDO.publisherUrlUtf8, torrentFile.info.publisherUrlUtf8)
                //ration
                if (ration != null) {
                    set(TorrentDO.ration, ration!!.ration)
                    set(TorrentDO.rationStartTime, ration!!.startTime)
                    set(TorrentDO.rationEndTime, ration!!.endTime)
                }
                where { TorrentDO.infoHash eq infoHash }
            }
        } else {
            database().insertAndGenerateKey(TorrentDO) {
                set(TorrentDO.infoHash, infoHash)
                set(TorrentDO.title, title)
                set(TorrentDO.category, category.code)
                //  set(Torrent.completeCount)
                set(TorrentDO.coverPath, coverPath?.absolutePath?.replaceFirst(torrentPath, ""))
                set(TorrentDO.createTime, createTime)
                set(TorrentDO.updateTime, updateTime)
                set(TorrentDO.status, status)
                //description
                set(TorrentDO.descImgs, description.imgs?.map { it.absolutePath.replaceFirst(torrentPath, "") })
                set(TorrentDO.description, description.content)
                //torrent
                set(TorrentDO.announce, torrentFile.announce)
                set(TorrentDO.announceList, torrentFile.announceList)
                set(TorrentDO.comment, torrentFile.comment)
                set(TorrentDO.commentUtf8, torrentFile.commentUtf8)
                set(TorrentDO.creationDate, torrentFile.creationDate)
                set(TorrentDO.encoding, torrentFile.encoding)
                set(TorrentDO.nodes, torrentFile.nodes)
                //info
                set(TorrentDO.length, torrentFile.info.length)
                set(TorrentDO.files, torrentFile.info.files)
                set(TorrentDO.name, torrentFile.info.name)
                set(TorrentDO.nameUtf8, torrentFile.info.nameUtf8)
                set(TorrentDO.pieceLength, torrentFile.info.pieceLength)
                set(TorrentDO.pieces, torrentFile.info.pieces.array())
                set(TorrentDO.publisher, torrentFile.info.publisher)
                set(TorrentDO.publisherUtf8, torrentFile.info.publisherUtf8)
                set(TorrentDO.publisherUrl, torrentFile.info.publisherUrl)
                set(TorrentDO.publisherUrlUtf8, torrentFile.info.publisherUrlUtf8)
                //ration
                if (ration != null) {
                    set(TorrentDO.ration, ration!!.ration)
                    set(TorrentDO.rationStartTime, ration!!.startTime)
                    set(TorrentDO.rationEndTime, ration!!.endTime)
                }
            }

        }
    }


}


/**
 * 实体工厂
 */
object TorrentFactory {

    /**
     * 从数据库中获取
     */
    fun findFromDb(infoHash: String): TorrentDO {
        val labels = database().from(com.github.blanexie.nexusj.torrent.infra.repository.Label).select()
            .where {
                TorrentDO.infoHash eq infoHash
            }.map { row ->
                val name = row[com.github.blanexie.nexusj.torrent.infra.repository.Label.name]
                val desc = row[com.github.blanexie.nexusj.torrent.infra.repository.Label.desc]
                Label(name!!, desc!!)
            }

        return database().from(TorrentDO).select()
            .where {
                TorrentDO.infoHash eq infoHash
            }.limit(1).map { row ->
                val title = row[TorrentDO.title]
                val category = Category.getByCode(row[TorrentDO.category]!!)
                val status = row[TorrentDO.status]
                val createTime = row[TorrentDO.createTime]
                val updateTime = row[TorrentDO.updateTime]

                val coverPath = File(torrentPath + row[TorrentDO.coverPath])

                val description = row[TorrentDO.description]
                val descImgs = row[TorrentDO.descImgs]?.map { File(torrentPath + it) }

                val announce = row[TorrentDO.announce]
                val announceList = row[TorrentDO.announceList]
                val comment = row[TorrentDO.comment]
                val commentUtf8 = row[TorrentDO.commentUtf8]
                val creationDate = row[TorrentDO.creationDate]
                val encoding = row[TorrentDO.encoding]
                val nodes = row[TorrentDO.nodes]

                val name = row[TorrentDO.name]
                var length = row[TorrentDO.length]
                val nameUtf8 = row[TorrentDO.nameUtf8]
                val pieceLength = row[TorrentDO.pieceLength]
                val pieces = row[TorrentDO.pieces]
                val publisher = row[TorrentDO.publisher]
                val publisherUtf8 = row[TorrentDO.publisherUtf8]
                val publisherUrl = row[TorrentDO.publisherUrl]
                val publisherUrlUtf8 = row[TorrentDO.publisherUrlUtf8]
                val files = row[TorrentDO.files]

                val info = Info(
                    length, files, name!!, nameUtf8, pieceLength!!, ByteBuffer.wrap(pieces),
                    publisher, publisherUtf8, publisherUrl, publisherUrlUtf8,
                )

                val torrentFile = TorrentFile(
                    infoHash, announce, announceList, comment, commentUtf8, creationDate, encoding, nodes, info
                )

                val ration = row[TorrentDO.ration]
                val rationStart = row[TorrentDO.rationStartTime]
                val rationEnd = row[TorrentDO.rationEndTime]
                if (ration != null) {
                    val ration1 = Ration(ration!!, rationStart!!, rationEnd!!)
                    return TorrentEntity(
                        infoHash, title!!, ration1, torrentFile, category, labels, coverPath,
                        Description(description!!, descImgs), status!!, createTime!!, updateTime!!
                    )
                }

                return TorrentEntity(
                    infoHash, title!!, null, torrentFile, category, labels, coverPath,
                    Description(description!!, descImgs), status!!, createTime!!, updateTime!!
                )
            }.last()
    }

    /**
     * 用户上传 种子的处理
     */
    fun upload(reqMap: Map<String, *>): TorrentDO {
        val title = reqMap["title"]!!.toStr()
        val category = Category.getByCode(reqMap["category"]!!.toStr())
        var label: List<Label> = JSONUtil.toList(reqMap["title"]!!.toStr(), Label::class.java)

        var torrent = reqMap["torrent"] as InputStream //:  Fi
        val torrentFile = TorrentFile.create(torrent.readAllBytes())
        val infoHash: String = torrentFile.infoHash

        val uploadFiles = reqMap["uploadFiles"]?.toList()?.map { it as UploadFile }
        val coverPath = uploadFiles?.first { it.name == "coverPath" }
        val coverPathFile = File("$infoHash/cover.${coverPath!!.suffix}")
        val writeFromStream = FileUtil.writeFromStream(coverPath.inputStream, coverPathFile)
        val descImgs = uploadFiles.filter { it.name != "coverPath" }.map {
            val file = File("$infoHash/${it.name}.${coverPath!!.suffix}")
            FileUtil.writeFromStream(it.inputStream, file)
        }

        val description = reqMap["description"]!!.toStr() //:  File?,//封面, 有些资源没有封面, 比如小说等

        val ration = reqMap["ration"] as Float?
        val rationStart = reqMap["rationStart"] as LocalDateTime?
        val rationEnd = reqMap["rationEnd"] as LocalDateTime?
        if (ration != null) {
            return TorrentEntity(
                infoHash, title, Ration(ration, rationStart!!, rationEnd!!), torrentFile, category,
                label, writeFromStream, Description(description, descImgs)
            )

        }
        return TorrentEntity(
            infoHash, title, null, torrentFile, category, label, writeFromStream,
            Description(description, descImgs)
        )
    }

}

fun main(){
    val classPathResource = ClassPathResource("aaa.torrent")
    val readBytes = classPathResource.readBytes()
    val create = TorrentFile.create(readBytes)
    println(create)
}